package org.zoomdev.zoom.aop.modules;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import java.util.Map;

import static org.objectweb.asm.Opcodes.*;

public final class CopyMethodVisitor extends ClassVisitor {

    private final String className;

    private final Map<String, MethodWithTypeConfig> replaceConfig;
    MethodWithTypeConfig config;


    public CopyMethodVisitor(ClassVisitor classVisitor, String className, Map<String, MethodWithTypeConfig> replaceConfig) {
        super(ASM9, classVisitor);
        this.className = className;
        this.replaceConfig = replaceConfig;
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
        super.visit(version, access, className, signature, superName, interfaces);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
        //System.out.println("visit method:" + name + "====> " + descriptor);

        if (name.equals("<init>")) {
            return super.visitMethod(access, name, descriptor, signature, exceptions);
        }

        String key = name + descriptor;
        config = replaceConfig.get(key);
        if (config == null) {
            return null;
        }
        MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
        return new MethodVisitor(Opcodes.ASM9, mv) {

            @Override
            public void visitTypeInsn(int opcode, String type) {
                if (opcode == NEW) {
                    if (type.equals(config.getType())) {
                        type = config.getReplaceType();
                    }
                }
                super.visitTypeInsn(opcode, type);
            }


            @Override
            public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
                if (opcode == GETFIELD) {
                    owner = className;
                }
                super.visitFieldInsn(opcode, owner, name, descriptor);
            }

            @Override
            public void visitMethodInsn(int opcode, String owner, String name,
                                        String descriptor, boolean isInterface) {
                if (opcode == Opcodes.INVOKESPECIAL && owner.equals(config.getType())) {
                    owner = config.getReplaceType();
                }
                super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
            }
        };
    }


}